package com.luozm.captcha;


import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.*;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;


/**
 * 拼图区域控件
 * Created by luozhanming on 2018/1/17.
 */

 class PictureVertifyView extends Image implements Component.DrawTask {

    //状态码
    private static final int STATE_DOWN = 1;
    private static final int STATE_MOVE = 2;
    private static final int STATE_LOOSEN = 3;
    private static final int STATE_IDEL = 4;
    private static final int STATE_ACCESS = 5;
    private static final int STATE_UNACCESS = 6;


    private static final int TOLERANCE = 10;         //验证的最大容差


    private int mState = STATE_IDEL;    //当前状态
    private PositionInfo shadowInfo;    //拼图缺块阴影的位置
    private PositionInfo blockInfo;     //拼图缺块的位置
    private PixelMap verfityBlock;        //拼图缺块Bitmap
    private Path blockShape;            //拼图缺块形状
    private Paint bitmapPaint;         //绘制拼图缺块的画笔
    private Paint shadowPaint;         //绘制拼图缺块阴影的画笔
    private long startTouchTime;       //滑动/触动开始时间
    private long looseTime;            //滑动/触动松开时间
    private int blockSize = 50;
    private boolean mTouchEnable = true;   //是否可触动

    private Callback callback;

    private CaptchaStrategy mStrategy;

    private int mMode;                //Captcha验证模式

    @Override
    public void invalidate() {
        super.invalidate();
        addDrawTask(this::onDraw);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        initDrawElements();
        if (mState != STATE_ACCESS) {
            canvas.drawPath(blockShape, shadowPaint);
        }
        if (mState == STATE_MOVE || mState == STATE_IDEL || mState == STATE_DOWN || mState == STATE_UNACCESS) {
            canvas.drawPixelMapHolder(new PixelMapHolder(verfityBlock), blockInfo.left, blockInfo.top, bitmapPaint);
        }
    }


    interface Callback {
        void onSuccess(long time);

        void onFailed();
    }

    public PictureVertifyView(Context context) {
        super(context);
    }

    public PictureVertifyView(Context context, AttrSet attrs) {
        super(context, attrs);
        mStrategy = new DefaultCaptchaStrategy(context);
        shadowPaint = mStrategy.getBlockShadowPaint();
        bitmapPaint = mStrategy.getBlockBitmapPaint();
        setTouchEventListener(new TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                if (mMode == Captcha.MODE_NONBAR && verfityBlock != null&& mTouchEnable) {
                    MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());
                    float x = point.getX();
                    float y = point.getY();

                    switch (touchEvent.getAction()) {
                        case TouchEvent.PRIMARY_POINT_DOWN:
                            if (x < blockInfo.left || y > blockInfo.left + blockSize || y < blockInfo.top || y > blockInfo.top + blockSize) {
                                return false;
                            }

                            downByTouch(x, y);
                            tempX = x;
                            tempY = y;
                            break;
                        case TouchEvent.PRIMARY_POINT_UP:
                            loose();
                            break;
                        case TouchEvent.POINT_MOVE:
//                            if (x < blockInfo.left || y > blockInfo.left + blockSize || y < blockInfo.top || y > blockInfo.top + blockSize) {
//                                return false;
//                            }
                             y=Utils.sub(y,300);
                            float offsetX = Utils.sub(x , tempX);
                            float offsetY = Utils.sub(y , tempY);
                            moveByTouch(offsetX, offsetY);
                            tempX = x;
                            tempY = y;
                            break;
                        default:
                            break;
                    }

                }
                return true;

            }
        });

    }
    private void initDrawElements() {
        if (shadowInfo == null) {
            shadowInfo = mStrategy.getBlockPostionInfo(getWidth(), getHeight(), blockSize);
            if (mMode == Captcha.MODE_BAR) {
                blockInfo = new PositionInfo(0, shadowInfo.top);
            } else {
                blockInfo = mStrategy.getPositionInfoForSwipeBlock(getWidth(), getHeight(), blockSize);
                System.out.println(getWidth()+"______" +getHeight()+"   blockInfo=="+blockInfo.left+"__"+blockInfo.top);
            }
        }
        if (blockShape == null) {
            blockShape = mStrategy.getBlockShape(blockSize);
            blockShape.offset(shadowInfo.left, shadowInfo.top);
        }
        if (verfityBlock == null) {
            verfityBlock = createBlockBitmap();
        }
    }


    /**
     * 按下滑动条(滑动条模式)
     *
     * @param progress  progress
     */
    void down(int progress) {
        startTouchTime = System.currentTimeMillis();
        mState = STATE_DOWN;
        blockInfo.left = (int) (progress / 100f * (getWidth() - blockSize));
        invalidate();
    }

    /**
     * 触动拼图块(触动模式)
     *
     * @param x  x坐标
     * @param y  y坐标
     */
    void downByTouch(float x, float y) {
        mState = STATE_DOWN;
//        blockInfo.left = (int) (x - blockSize / 2f);
        blockInfo.left =(int)Utils.sub(x,Utils.div(blockSize, 2f));
//        blockInfo.top = (int) (y - blockSize / 2f);
        blockInfo.top = (int) Utils.sub(y,Utils.div(blockSize, 2f));
        startTouchTime = System.currentTimeMillis();
        System.out.println("downByTouch===="+blockInfo.left+ "____"+blockInfo.top);
        invalidate();
    }

    /**
     * 移动拼图缺块(滑动条模式)
     *
     * @param progress  progress
     */
    void move(int progress) {
        mState = STATE_MOVE;
        blockInfo.left = (int) (progress / 100f * (getWidth() - blockSize));
        invalidate();
    }

    /**
     * 触动拼图缺块(触动模式)
     *
     * @param offsetX x偏移
     * @param offsetY y偏移
     */
    void moveByTouch(float offsetX, float offsetY) {
        mState = STATE_MOVE;
//        blockInfo.left += offsetX;
        blockInfo.left = (int) Utils.add(blockInfo.left,offsetX);
//        blockInfo.top += offsetY;
        blockInfo.top = (int) Utils.add(blockInfo.top,offsetY);
        System.out.println("moveByTouch===="+blockInfo.left+ "_____"+blockInfo.top);
        invalidate();
    }

    /**
     * 松开
     */
    void loose() {
        mState = STATE_LOOSEN;
        looseTime = System.currentTimeMillis();
        checkAccess();
        invalidate();
    }


    /**
     * 复位
     */
    void reset() {
        mState = STATE_IDEL;
        verfityBlock = null;
        shadowInfo = null;
        blockShape = null;
        invalidate();
    }

    void unAccess() {
        mState = STATE_UNACCESS;
        invalidate();
    }

    void access() {
        mState = STATE_ACCESS;
        invalidate();
    }

    void callback(Callback callback) {
        this.callback = callback;
    }


    void setCaptchaStrategy(CaptchaStrategy strategy) {
        this.mStrategy = strategy;
    }

    void setBlockSize(int size) {
        this.blockSize = size;
        this.blockShape = null;
        this.blockInfo = null;
        this.shadowInfo = null;
        this.verfityBlock = null;
        invalidate();
    }
    public void setBitmap(int resource) {
        this.blockShape = null;
        this.blockInfo = null;
        this.shadowInfo = null;
        this.verfityBlock.release();
        this.verfityBlock = null;
        setImageAndDecodeBounds(resource);
//        setPixelMap(resource);
    }

    public void setBitmap(PixelMap resource) {
        this.blockShape = null;
        this.blockInfo = null;
        this.shadowInfo = null;
        this.verfityBlock.release();
        this.verfityBlock = null;
        PixelMapElement pixelMapElement = new PixelMapElement(resource);
        pixelMapElement.setBounds(0,0,getWidth(),getHeight());
        setImageElement(pixelMapElement);
//        setPixelMap(resource);
    }


    public void setBitmap(Element resource) {
        this.blockShape = null;
        this.blockInfo = null;
        this.shadowInfo = null;
        this.verfityBlock.release();
        this.verfityBlock = null;
//        setPixelMap(resource);
        setImageElement(resource);
    }

    public void setMode(int mode) {
        this.mMode = mode;
        this.blockShape = null;
        this.blockInfo = null;
        this.shadowInfo = null;
        this.verfityBlock = null;
        invalidate();
    }



    void setTouchEnable(boolean enable) {
        this.mTouchEnable = enable;
    }

    /**
     * 生成拼图缺块的Bitmap
     *
     * @return PixelMap
     */
    private PixelMap createBlockBitmap() {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(getWidth(), getHeight());
        PixelMap tempBitmap = PixelMap.create(getPixelMap(),initializationOptions);

        Canvas canvas = new Canvas(new Texture(tempBitmap));
        Element imageElement = getImageElement();
        imageElement.setBounds(0, 0, getWidth(), getHeight());
        canvas.clipPath(blockShape, Canvas.ClipOp.INTERSECT);
        imageElement.drawToCanvas(canvas);
        mStrategy.decoreateSwipeBlockBitmap(canvas, blockShape);
        return cropBitmap(tempBitmap);
    }

    /**
     * 保留拼图缺块大小的bitmap
     *
     * @param bmp PixelMap
     * @return PixelMap
     */
    private PixelMap cropBitmap(PixelMap bmp) {
        PixelMap result = null;
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(blockSize, blockSize);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        result = PixelMap.create(bmp, new Rect(shadowInfo.left, shadowInfo.top, blockSize, blockSize), initializationOptions);
        bmp.release();
        return result;
    }

    /**
     * 检测是否通过
     */
    private void checkAccess() {
        if (Math.abs(blockInfo.left - shadowInfo.left) < TOLERANCE && Math.abs(blockInfo.top - shadowInfo.top) < TOLERANCE) {
            access();
            if (callback != null) {
                long deltaTime = looseTime - startTouchTime;
                callback.onSuccess(deltaTime);
            }
        } else {
            unAccess();
            if (callback != null) {
                callback.onFailed();
            }
        }
    }

    private float tempX, tempY;



}
